﻿module IronLua.Internals.baselib
//
//open IronLua
//open IronLua.Runtime
//open IronLua.Internals.api
//open IronLua.Internals.auxlib
//
//let openbaselib thread = 
//    api.pushglobaltable(thread)
//    api.pushglobaltable(thread)
//    api.setfield(thread, -2, "_G")
//    api.pushliteral(thread, api.LUA_VERSION)
//    api.setfield(thread, -2, "_VERSION")
//
//type globals = 
//    class
//
//        static member assert' (thread : Thread) (scope : Scope) = 
//            if not(api.toboolean(thread, 1))
//            then auxlib.errormsg(thread, auxlib.optstring(thread, 2, "assertion failed!"))
//            else api.gettop(thread)            
//            
//        static member collectgarbage (thread : Thread) (scope : Scope) = 
//            // TODO: this is not supported atm
//            api.pushinteger(thread, 0)
//            1
//
//        static member dofile (thread : Thread) (scope : Scope) = 
//            let fname = auxlib.optstring(thread, 1, "")
//            api.settop(thread, 1)
//            if(auxlib.loadfile(thread, fname) <> LuaResult.OK) then 
//                api.error(thread)
//            else 
//                api.callk(thread, 0, api.LUA_MULTRET, 0, LuaPrototype(globals.dofilecont))
//                globals.dofilecont thread null
//
//        static member error (thread : Thread) (scope : Scope) = 
//            let level = auxlib.optint(thread, 2, 1)
//            api.settop(thread, 1)
//            if api.isstring(thread, 1) && level > 0 then 
//                do auxlib.where(thread, level)
//                do api.pushvalue(thread, 1)
//                do api.concat(thread, 2)            
//            api.error(thread)            
//
//        static member getmetatable (thread : Thread) (scope : Scope) = 
//            auxlib.checkany(thread, 1)
//            if not(api.getmetatable(thread, 1)) then
//                api.pushnil(thread)
//                1
//            else
//                auxlib.getmetafield(thread, 1, "__metatable") |> ignore
//                1            
//
//        static member ipairsaux (thread : Thread) (scope : Scope) = 
//            let i = auxlib.checkint(thread, 2) + 1
//            auxlib.checktype(thread, 1, LuaValueType.Table)
//            api.pushinteger(thread, i)
//            api.rawgeti(thread, 1, i)
//            if api.isnil(thread, -1) then 1 else 2
//
//        static member ipairs (thread : Thread) (scope : Scope) = 
//            globals.pairsmeta(thread, "__ipairs", true, LuaPrototype(globals.ipairsaux))
//
//        static member load (thread : Thread) (scope : Scope) = 
//            let top = api.gettop(thread)
//            let src, srclen = auxlib.tolstring(thread, 1)
//            let mode = auxlib.optstring(thread, 3, "bt")
//            let mutable status = LuaResult.OK
//            if src <> null then
//                let chunkname = auxlib.optstring(thread, 2, src)
//                status <- auxlib.loadbufferx(thread, src, srclen, chunkname, mode)
//            else
//                let chunkname = "=(load)"
//                auxlib.checktype(thread, 1, LuaValueType.Function)
//                api.settop(thread, api.RESERVEDSLOT)
//                status <- api.load(thread, globals.genericreader, null, chunkname, mode)
//            if status = LuaResult.OK && top >= 4 then
//                api.pushvalue(thread, 4)
//                api.setupvalue(thread, -2, 1) |> ignore
//            globals.loadaux(thread, status)
//
//        static member loadfile (thread : Thread) (scope : Scope) = 
//            let filename = auxlib.optstring(thread, 1, null)
//            let mode = auxlib.optstring(thread, 1, null)
//            let hasenv = not(api.isnone(thread, 3))
//            let status = auxlib.loadfilex(thread, filename, mode)
//            if status = LuaResult.OK && hasenv then
//                api.pushvalue(thread, 3)
//                api.setupvalue(thread, -2, 1) |> ignore            
//            globals.loadaux(thread, status)
//
//        static member next (thread : Thread) (scope : Scope) = 
//            auxlib.checktype(thread, 1, LuaValueType.Table)
//            api.settop(thread, 2)
//            if api.next(thread, 1) then 2
//            else api.pushnil(thread); 1
//          
//        static member pairs (thread : Thread) (scope : Scope) = 
//            globals.pairsmeta(thread, "__pairs", false, LuaPrototype(globals.next))
//
//        static member pcall (thread : Thread) (scope : Scope) = 
//            auxlib.checkany(thread, 1)
//            api.pushnil(thread)
//            api.insert(thread, 1)
//            let status = api.pcallk(thread, 
//                                    api.gettop(thread) - 2, 
//                                    api.LUA_MULTRET, 
//                                    0, 
//                                    0, 
//                                    LuaPrototype(globals.pcallcont))
//            let success = status = LuaResult.OK
//            globals.finishpcall(thread, success)
//
//        static member print (thread : Thread) (scope : Scope) =             
//            let n = api.gettop(thread)            
//            api.getglobal(thread, "tostring")
//            imperative {
//                for i in [1 .. n] do
//                    api.pushvalue(thread, -1)
//                    api.pushvalue(thread, i)
//                    api.call(thread, 1, 1)
//                    let str, len = auxlib.tolstring(thread, -1)
//                    if str = null then return auxlib.errormsg(thread, "'tostring' must return a string to 'print'")
//                    if i > 1 then thread.State.StdOut.Write('\t')
//                    thread.State.StdOut.Write(str)
//                    api.pop(thread, 1)
//            } |> ignore
//
//            thread.State.StdOut.WriteLine()
//            0
//
//        static member rawequal (thread : Thread) (scope : Scope) = 
//            auxlib.checkany(thread, 1)
//            auxlib.checkany(thread, 2)
//            api.pushboolean(thread, api.rawequal(thread, 1, 2))
//            1
//
//        static member rawget (thread : Thread) (scope : Scope) = 
//            auxlib.checktype(thread, 1, LuaValueType.Table)
//            auxlib.checkany(thread, 2)
//            api.settop(thread, 2)
//            api.rawget(thread, 1)
//            1
//
//        static member rawlen (thread : Thread) (scope : Scope) = 
//            let t = api.type'(thread, 1)
//            auxlib.argcheck(thread, 
//                            t = LuaValueType.Table || t = LuaValueType.String,
//                            1,
//                            "table or string expected")
//            api.pushinteger(thread, api.rawlen(thread, 1))
//            1
//
//        static member rawset (thread : Thread) (scope : Scope) = 
//            auxlib.checktype(thread, 1, LuaValueType.Table)
//            auxlib.checkany(thread, 2)
//            auxlib.checkany(thread, 3)
//            api.settop(thread, 3)
//            api.rawset(thread, 1)
//            1     
//
//        static member require (thread : Thread) (scope : Scope) = 
//            0
//
//        static member select (thread : Thread) (scope : Scope) = 
//            0
//
//        static member setmetatable (thread : Thread) (scope : Scope) = imperative {
//                let t = api.type'(thread, 2)
//                auxlib.checktype(thread, 1, LuaValueType.Table)
//                auxlib.argcheck(thread, 
//                                t = LuaValueType.Nil || t = LuaValueType.Table,
//                                2,
//                                "nil or table expected")
//                if auxlib.getmetafield(thread, 1, "__metatable") then                    
//                    return auxlib.errormsg(thread, "cannot change a protected metatable")
//
//                api.settop(thread, 2)
//                api.setmetatable(thread, 1) |> ignore
//                return 1
//            }         
//            
//        static member tonumber (thread : Thread) (scope : Scope) = imperative {            
//                if api.isnoneornil(thread, 2) then
//                    let n, isnum = api.tonumberx(thread, 1)
//                    if isnum then
//                        api.pushnumber(thread, n)
//                        return 1
//
//                    api.checkany(thread, 1)
//                else
//                    let str, len = auxlib.checklstring(thread, 1)
//                    let base' = auxlib.checkint(thread, 2)
//                    auxlib.argcheck(thread, 2 <= base' && base' <= 36, 2, "base out of range")                    
//                    let mutable num, ok = globals.tryconvnum(str, base')                    
//                    if ok then 
//                        api.pushnumber(thread, num)
//                        return 1
//
//                api.pushnil(thread)
//                return 1
//            }
//
//        static member tostring (thread : Thread) (scope : Scope) = 
//            api.checkany(thread, 1)            
//            auxlib.tolstring(thread, 1) |> ignore
//            1
//
//        static member type' (thread : Thread) (scope : Scope) = 
//            api.checkany(thread, 1)
//            api.pushstring(thread, auxlib.typename(thread, 1)) |> ignore
//            1
//
//        static member xpcall (thread : Thread) (scope : Scope) = 
//            let n = api.gettop(thread)
//            auxlib.argcheck(thread, n >= 2, 2, "value expected")
//            api.pushvalue(thread, 1)
//            api.copy(thread, 2, 1)
//            api.replace(thread, 2)
//            let status = api.pcallk(thread, 
//                                    n - 2, 
//                                    api.LUA_MULTRET, 
//                                    1, 
//                                    0, 
//                                    LuaPrototype(globals.pcallcont))
//            let success = status = LuaResult.OK
//            globals.finishpcall(thread, success)
//
//        (* helpers *)
//
//        static member tryconvnum(str : string, b : int) = 
//            try
//                let n = System.Convert.ToInt64(str, b)
//                (LuaValue.fromInt64(n), true)
//            with 
//            | _ -> (LuaValue.fromInt64(0L), false)   
//
//        static member dofilecont (thread : Thread) (scope : Scope) = 
//            api.gettop(thread) - 1 
//
//        static member genericreader (thread, ud) = imperative {
//                auxlib.checkstack(thread, 2, "too many nested functions")
//                api.pushvalue(thread, 1)
//                api.call(thread, 0, 1)
//                if(api.isnil(thread, -1)) then return null
//            
//                if not(api.isstring(thread, -1)) then 
//                    auxlib.errormsg(thread, "reader function must return a string") |> ignore
//
//                api.replace(thread, api.RESERVEDSLOT)
//                return fst(auxlib.tolstring(thread, api.RESERVEDSLOT))
//            }        
//
//        static member loadaux (thread, status) : int =
//            if status = LuaResult.OK then
//                1
//            else
//                api.pushnil(thread)
//                api.insert(thread, -2)
//                2
//
//        static member pairsmeta (thread : Thread, method' : string, iszero : bool, iter : LuaPrototype) =
//            if not(auxlib.getmetafield(thread, 1, method')) then
//                auxlib.checktype(thread, 1, LuaValueType.Table)
//                api.pushclrfunction(thread, iter)
//                api.pushvalue(thread, 1)
//                if iszero then api.pushinteger(thread, 0)
//                else api.pushnil(thread)
//            else
//                api.pushvalue(thread, 1)
//                api.call(thread, 1, 3)
//            3
//
//        static member finishpcall(thread : Thread, success : bool) : int = imperative {
//                if not(api.checkstack(thread, 1)) then
//                    api.settop(thread, 0)
//                    api.pushboolean(thread, success)
//                    api.pushstring(thread, "stack overflow") |> ignore
//                    return 2
//                api.pushboolean(thread, success)
//                api.replace(thread, 1)
//                return api.gettop(thread)
//            }
//
//        static member pcallcont (thread : Thread) (scope : Scope) = 
//            let status, ctx = api.getctx(thread)
//            let success = status = LuaResult.Yield
//            globals.finishpcall(thread, success)
//            
//    end
//
//type debug =  
//    class
//
//        static member debug (thread : Thread) (scope : Scope) = 
//            0
//
//        static member gethook (thread : Thread) (scope : Scope) = 
//            0
//
//        static member getinfo (thread : Thread) (scope : Scope) = 
//            0
//
//        static member getlocal (thread : Thread) (scope : Scope) = 
//            0
//
//        static member getmetatable (thread : Thread) (scope : Scope) = 
//            0
//
//        static member getregistry (thread : Thread) (scope : Scope) = 
//            0
//
//        static member getupvalue (thread : Thread) (scope : Scope) = 
//            0
//
//        static member getuservalue (thread : Thread) (scope : Scope) = 
//            0
//
//        static member sethook (thread : Thread) (scope : Scope) = 
//            0
//
//        static member setlocal (thread : Thread) (scope : Scope) = 
//            0
//
//        static member setupvalue (thread : Thread) (scope : Scope) = 
//            0
//
//        static member setuservalue (thread : Thread) (scope : Scope) = 
//            0
//
//        static member traceback (thread : Thread) (scope : Scope) = 
//            0
//
//        static member upvaluejoin (thread : Thread) (scope : Scope) = 
//            0
//
//    end
//                                
//type coroutine =
//    class
//       
//        static member create (thread : Thread) (scope : Scope) = 
//            let fn = thread.Stack.pop()
//            // ensure that fn is a function
//            let newcoro = thread.CreateCoroutine(fn)
//            thread.Stack.push(newcoro)
//            1
//       
//        static member resume (thread : Thread) (scope : Scope) = 
//            let coro = thread.Stack.pop() :?> Thread // rewrite
//            // ensure that coro is a thread
//            thread.Stack.moveTo(coro, -1, -1)
//            coro.ResumeExecution()
//            -1
//
//        static member running (thread : Thread) (scope : Scope) = 
//            let coro = thread.Stack.pop() :?> Thread // rewrite
//            // ensure that coro is a thread
//            thread.Stack.push(thread.clrThread.ManagedThreadId = coro.clrThread.ManagedThreadId)
//            1
//
//        static member status (thread : Thread) (scope : Scope) = 
//            0
//
//        static member wrap (thread : Thread) (scope : Scope) = 
//            0
//
//        static member yield' (thread : Thread) (scope : Scope) = 
//            thread.Stack.moveTo(thread.OwnerThread, -1, -1)
//            thread.YieldExecution()
//            -1
//    end
//
//let internal retrieveHostIncludes() : ((string * obj) array) = 
//    [| |]
//
//let internal selfglobal (g : Table) = 
//    // g.entries.Add(String("_G"), g)    
//    g
//        
//let internal makeGlobals () = new Table()
//    (*
//    Table.fromHash([|  ("coroutine", Table.fromHash [| ("create",  coroutine.create  |> LuaPrototype.fromFunc)  
//                                                       ("resume",  coroutine.resume  |> LuaPrototype.fromFunc)  
//                                                       ("running", coroutine.running |> LuaPrototype.fromFunc)  
//                                                       ("status",  coroutine.status  |> LuaPrototype.fromFunc)  
//                                                       ("wrap",    coroutine.wrap    |> LuaPrototype.fromFunc)  
//                                                       ("yield",   coroutine.yield'  |> LuaPrototype.fromFunc) |]);
//                       ("assert",   globals.assert' |> LuaPrototype.fromFunc );
//                       ("collectgarbage", globals.collectgarbage |> LuaPrototype.fromFunc );
//                       ("dofile",   globals.dofile |> LuaPrototype.fromFunc );
//                       ("error",    globals.error |> LuaPrototype.fromFunc );
//                       ("getmetatable", globals.getmetatable |> LuaPrototype.fromFunc );
//                       ("ipairs",   globals.ipairs |> LuaPrototype.fromFunc );
//                       ("load",     globals.load |> LuaPrototype.fromFunc );
//                       ("loadfile", globals.loadfile |> LuaPrototype.fromFunc );
//                       ("next",     globals.next |> LuaPrototype.fromFunc );
//                       ("pairs",    globals.pairs |> LuaPrototype.fromFunc );
//                       ("pcall",    globals.pcall |> LuaPrototype.fromFunc );
//                       ("print",    globals.print |> LuaPrototype.fromFunc );
//                       ("rawequal", globals.rawequal |> LuaPrototype.fromFunc );
//                       ("rawget",   globals.rawget |> LuaPrototype.fromFunc );
//                       ("rawlen",   globals.rawlen |> LuaPrototype.fromFunc );
//                       ("rawset",   globals.rawset |> LuaPrototype.fromFunc );
//                       ("require",  globals.require |> LuaPrototype.fromFunc );
//                       ("select",   globals.select |> LuaPrototype.fromFunc );
//                       ("setmetatable", globals.setmetatable |> LuaPrototype.fromFunc );
//                       ("tonumber", globals.tonumber |> LuaPrototype.fromFunc );
//                       ("tostring", globals.tostring |> LuaPrototype.fromFunc );
//                       ("type",     globals.type' |> LuaPrototype.fromFunc );                       
//                       ("xpcall",   globals.xpcall |> LuaPrototype.fromFunc );
//                    |] |> Array.append (retrieveHostIncludes()) 
//                       |> Array.append [| ("_VERSION", (String("Lua 5.2 (IronLua)")) :> ILuaValue) |])                            
//                    |> selfglobal
//    *)